package com.lnking.lnkingplace.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.deepoove.poi.XWPFTemplate;

import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.lnking.lnkingplace.Util.*;
import com.lnking.lnkingplace.mapper.IsolationPersonnelMapper;
import com.lnking.lnkingplace.mapper.IsolationPlaceMapper;
import com.lnking.lnkingplace.mapper.IsolationRoomMapper;
import com.lnking.lnkingplace.model.dto.isolation.personnel.IdCardImportDto;
import com.lnking.lnkingplace.model.dto.isolation.personnel.PersonnelImportDto;
import com.lnking.lnkingplace.model.dto.isolation.personnel.PersonnelWordDto;
import com.lnking.lnkingplace.model.entity.IsolationPersonnel;
import com.lnking.lnkingplace.model.entity.Leaders;
import com.lnking.lnkingplace.model.enums.DateFormat;
import com.lnking.lnkingplace.model.enums.MoveType;
import com.lnking.lnkingplace.model.enums.ProcessStatus;
import com.lnking.lnkingplace.model.enums.RoomType;
import com.lnking.lnkingplace.model.login.SmsLoginRequest;
import com.lnking.lnkingplace.model.request.isolation.personnel.*;
import com.lnking.lnkingplace.service.IIsolationPersonnelService;
import com.lnking.lnkingplace.service.ILoginService;
import com.lnking.starter.export.utils.ImportOption;
import com.lnking.starter.export.utils.ImportUtils;
import com.lnking.starter.mybatis.service.impl.CustomServiceImpl;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhangqt
 * @since 2022-08-27
 */
@Service
public class IsolationPersonnelServiceImpl extends CustomServiceImpl<IsolationPersonnelMapper, IsolationPersonnel> implements IIsolationPersonnelService {

    @Resource
    UserUtil userUtil;

    @Resource
    IsolationPlaceMapper isolationPlaceMapper;
    @Resource
    IsolationRoomMapper isolationRoomMapper;

    final Integer DAY = 7;

    final Integer HOME_DAY = 3;

    final String PWD = "123456";

    @Autowired
    ILoginService loginService;

    @Resource
    QrcodeUtil qrcodeUtil;

    @Value("${upload.pdf}")
    String pdfLocation;

    public static final String TRUE="是";

    @Override
    public void updateInfo(UpdateInfoRequest params) {
        String idCard = params.getIdCard();
        LambdaQueryWrapper<IsolationPersonnel> query = new LambdaQueryWrapper<>();
        query.eq(IsolationPersonnel::getIdCard,idCard);
        IsolationPersonnel data = this.baseMapper.selectOne(query);

        String sex = IdCardUtil.getSex(idCard);
        Integer age = IdCardUtil.getAge(idCard);
        if(null != data){
            data.setSex(sex);
            data.setAge(age);
            data.setIdCard(idCard);
            data.setName(params.getName());
            this.baseMapper.updateById(data);
        }
        else{
            IsolationPersonnel info = new IsolationPersonnel();
            BeanUtils.copyProperties(params,info);
            info.setSex(sex);
            info.setAge(age);
            info.setCreateTime(LocalDateTime.now());
            this.baseMapper.insert(info);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void distributeRoom(DistributeRoomRequest params) {
        //按同行查询
        List<IsolationPersonnel> list = this.getDataByUnionFlag(params.getId());
        String placeId = isolationPlaceMapper.getPlaceId(params.getPlaceName());
        list.forEach(r->{
            //填入房号
            r.setRoomNumber(params.getRoom());
            r.setPlaceId(placeId);
            r.setCreateTime(LocalDateTime.now());
            this.updateById(r);
        });
        //修改房间状态
        isolationRoomMapper.updateStatus(placeId,params.getRoom(), RoomType.USEING);
    }

    @Override
    public List<IsolationPersonnel> getDataByUnionFlag(String id) {
        LambdaQueryWrapper<IsolationPersonnel> query = new LambdaQueryWrapper<>();
        query.eq(IsolationPersonnel::getUnionFlag,id);
        List<IsolationPersonnel> result = this.baseMapper.selectList(query);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRoom(UpdateRoomRequest params) {
        LambdaQueryWrapper<IsolationPersonnel> query = new LambdaQueryWrapper<>();
        query.eq(IsolationPersonnel::getIdCard,params.getIdCard());
        IsolationPersonnel info = this.baseMapper.selectOne(query);
        Assert.isTrue(null != info, "身份证号不存在");
        info.setRoomNumber(params.getRoom());
        String placeId = isolationPlaceMapper.getPlaceId(params.getPlaceName());
        info.setPlaceId(placeId);
        this.baseMapper.updateById(info);

        //查询家庭成员
        List<IsolationPersonnel> list = this.baseMapper.getFamily(info.getId());
        if(null != list && list.size() > 0){
            list.forEach(r ->{
                r.setRoomNumber(params.getRoom());
                r.setPlaceId(placeId);
                this.baseMapper.updateById(r);
            });
        }

    }

    @Override
    public void updateBatchType(List<UpdateBatchType> data) {
        data.forEach(d ->{
            IsolationPersonnel info = new IsolationPersonnel();
            info.setId(d.getId());
            if(StringUtils.isNotBlank(d.getPersonnelType())){
                info.setPersonnelType(d.getPersonnelType());
            }
            if(StringUtils.isNotBlank(d.getMoveStatus())){
                info.setMoveStatus(d.getMoveStatus());
            }
            this.baseMapper.updateById(info);
        });
    }

    @Override
    public void exportWord(String id, HttpServletResponse response)throws Exception {
        PersonnelWordDto user = this.baseMapper.getWordData(id);
        //本地获取路径
        String path = Thread.currentThread().getContextClassLoader().getResource("").getPath()+"/word/template.docx";
        //解决打成jar后获取不到路径
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("word/template.docx");
        XWPFTemplate template = XWPFTemplate.compile(inputStream).render(getData(id));
        String name=user.getName();
        String filename = URLEncoder.encode(name+"-隔离解除告知书.docx", "UTF-8");
        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition","attachment;filename="+ filename);
        OutputStream out = response.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(out);
        template.write(bos);
        bos.flush();
        out.flush();

        //关闭资源
        out.close();
        bos.close();
        template.close();
    }




    @Override
    public void exportPdf(String id, HttpServletResponse response) throws IOException {
        PersonnelWordDto user = this.baseMapper.getWordData(id);
        //本地获取路径
        //解决打成jar后获取不到路径
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("word/template.pdf");

        String name=user.getName();
        String filename = URLEncoder.encode(name+"-隔离解除告知书.pdf", "UTF-8");
        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition","attachment;filename="+ filename);
        OutputStream out = response.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(out);
        PdfStamper ps = null;
        PdfReader reader = null;

        try {
            // 2 读入pdf表单
            assert inputStream != null;
            reader = new PdfReader(inputStream);
            // 3 根据表单生成一个新的pdf
            ps = new PdfStamper(reader, bos);
            // 4 获取pdf表单
            AcroFields form = ps.getAcroFields();
            // 5给表单添加中文字体
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            form.addSubstitutionFont(base);

            // 6查询数据================================================
            Map<String, Object> data = getData(id);
            // 7遍历data 给pdf表单表格赋值
            for (String key : data.keySet()) {
                form.setFieldProperty(key, "textsize", 15.9f, null);
                form.setField(key, data.get(key).toString());
            }
            ps.setFormFlattening(true);

            // 加上盖章
//            ImageStamp.imageStamp(ps);


            System.out.println("===============PDF导出成功=============");
        } catch (Exception e) {
            System.out.println("===============PDF导出失败=============");
            e.printStackTrace();
        } finally {
            try {
                ps.close();
                out.close();
                reader.close();
                bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void exportPdfs(List<String> ids, HttpServletResponse response) throws IOException {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
        LocalDateTime localDateTime = LocalDateTime.now();
        String dateStr = localDateTime.format(fmt);
        String localhostPath=pdfLocation+dateStr+"/";
        List<String> fileNames = new ArrayList<String>();
        for (String id : ids) {
        PersonnelWordDto user = this.baseMapper.getWordData(id);
        //本地获取路径
        //解决打成jar后获取不到路径
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("word/template.pdf");
        // 模板文件路径
        String name=user.getName()+"-隔离解除告知书.pdf";
        // 生成的文件路径
        String outputFileName = localhostPath+name;
        java.io.File dest = new java.io.File(outputFileName);
        // 创建路径
        if(!dest.getParentFile().exists()) {
            dest.getParentFile().mkdir();
        }
        OutputStream os = null;
        PdfStamper ps = null;
        PdfReader reader = null;
            fileNames.add(outputFileName);
        try {
            os = new FileOutputStream(new File(outputFileName));
            // 2 读入pdf表单
            reader = new PdfReader(inputStream);
            // 3 根据表单生成一个新的pdf
            ps = new PdfStamper(reader, os);
            // 4 获取pdf表单
            AcroFields form = ps.getAcroFields();
            // 5给表单添加中文字体
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//            BaseFont bfComic4 = BaseFont.createFont("c:\\windows\\fonts\\SIMFANG.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            form.addSubstitutionFont(base);

            // 6查询数据================================================
            Map<String, Object> data = getData(id);
            // 7遍历data 给pdf表单表格赋值
            for (String key : data.keySet()) {
                form.setFieldProperty(key, "textsize", 15.9f, null);
                form.setField(key, data.get(key).toString());
            }
            ps.setFormFlattening(true);

            // 加上盖章
//            ImageStamp.imageStamp(ps);

            System.out.println("===============PDF导出成功=============");
        } catch (Exception e) {
            System.out.println("===============PDF导出失败=============");
            e.printStackTrace();
        } finally {
            try {
                ps.close();
                reader.close();
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        }

        //导出压缩文件的全路径
        String zipFilePath = localhostPath + "隔离解除告知书"+".zip";
        //导出zip
        File zip = new File(zipFilePath);
        //将excel文件生成压缩文件
        File srcfile[] = new File[fileNames.size()];
        for (int j = 0, n1 = fileNames.size(); j < n1; j++) {
            srcfile[j] = new File(fileNames.get(j));
        }
        ZipFiles(srcfile, zip);
        String filename = URLEncoder.encode("隔离解除告知书.zip", "UTF-8");
        response.setContentType("application/zip");
//        response.setHeader("Location",zip.getName());
        response.setHeader("Content-disposition","attachment;filename="+ filename);
        OutputStream outputStream = response.getOutputStream();
        InputStream inputStream = new FileInputStream(zipFilePath);
        byte[] buffer = new byte[1024];
        int i = -1;
        while ((i = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, i);
        }
        outputStream.flush();
        outputStream.close();
        inputStream.close();

//        //删除临时文件
//        for (String fileName : fileNames) {
//            new File(fileName).delete();
//        }
//       zip.delete();
//        new File(localhostPath).delete();
    }



    //压缩文件
    public void ZipFiles(File[] srcfile, File zipfile) {
        byte[] buf = new byte[1024];
        try {
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
                    zipfile));
            for (int i = 0; i < srcfile.length; i++) {
                FileInputStream in = new FileInputStream(srcfile[i]);
                out.putNextEntry(new ZipEntry(srcfile[i].getName()));
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                out.closeEntry();
                in.close();
            }
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }





    //获取解除通知书数据
    private Map<String,Object> getData(String id){
        PersonnelWordDto wordData = this.baseMapper.getWordData(id);
        Map<String,Object> data = JSON.parseObject(JSON.toJSONString(wordData), Map.class);
        data.put("day",wordData.getDays());
        data.put("homeDay",HOME_DAY);
        data.put("now",LocalDateTimeUtil.localDateTimeToString(LocalDateTime.now(),"yyyy年MM月dd日"));
        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importExcel(String placeId,MultipartFile file) throws Exception{
        ImportOption option = new ImportOption.Builder().build();
        List<PersonnelImportDto> result =  ImportUtils.importExcel(file, PersonnelImportDto.class,option);
        for(PersonnelImportDto dto : result){
            if(StringUtils.isNotBlank(dto.getPlaceName())){
                IsolationPersonnel info = new IsolationPersonnel();
                BeanUtils.copyProperties(dto,info);
                info.setUpdateTime(LocalDateTime.now());
                if(StringUtils.isNotBlank(dto.getAge())){
                    info.setAge(Integer.parseInt(dto.getAge()));
                }
                //todo 写入placeId
                //查询placeId
                placeId = isolationPlaceMapper.getPlaceId(dto.getPlaceName());
                Assert.isTrue(StringUtils.isNotBlank(placeId), "该场所不存在："+"【"+dto.getPlaceName()+"】");
                info.setPlaceId(placeId);
                if(null != dto.getPhone() && dto.getPhone().trim().length() > 11){
                    info.setPhone(null);
                }
                info.setIdCard(dto.getIdCard().trim());
                //处理时间
                if(StringUtils.isNotBlank(dto.getStartDate())){
                    LocalDateTime startTime = LocalDateTimeUtil.
                            stringToLocalDateTime(dto.getStartDate().replace("  "," "), DateFormat.LOCAL_DATE_MIN_LINE);
                    info.setCreateTime(startTime);
                }
                if(StringUtils.isNotBlank(dto.getEndDate())){
                    LocalDateTime endDate = LocalDateTimeUtil
                            .stringToLocalDateTime(dto.getEndDate().replace("  "," "), DateFormat.LOCAL_DATE_MIN_LINE);
                    info.setEndDate(endDate);
                }
                //查找人是否存在
                String idCard = info.getIdCard();
                IsolationPersonnel personnelInfo = check(idCard,info.getMoveStatus());
                if(null == personnelInfo){
                    this.baseMapper.insert(info);
                }
                else{
                    info.setId(personnelInfo.getId());
                    this.baseMapper.updateById(info);
                }
            }
        }
    }


    @Override
    public void importIdCard(MultipartFile file) throws Exception {
        ImportOption option = new ImportOption.Builder().build();
        List<IdCardImportDto> result =  ImportUtils.importExcel(file, IdCardImportDto.class,option);
        for (IdCardImportDto idCardImportDto : result.stream().filter(e->e.getIdCard()!=null).collect(Collectors.toList())) {
            IsolationPersonnel check = check(idCardImportDto.getIdCard(), null);
            check.setEndDate(LocalDateTime.now());
            check.setMoveStatus(TRUE);
            isolationRoomMapper.updateStatus(check.getPlaceId(),check.getRoomNumber(),RoomType.DIRTY_ROOM);
            updateById(check);
        }

    }


    private String getPlaceId(String placeId){
        if(StringUtils.isBlank(placeId)){
            String name = userUtil.getUser().getName();
            return isolationPlaceMapper.getPlaceId(name);
        }
        return placeId;
    }

    private IsolationPersonnel check(String idCard,String moveStatus){
        LambdaQueryWrapper<IsolationPersonnel> query = new LambdaQueryWrapper<>();
        query.eq(IsolationPersonnel::getIdCard,idCard);
//                .eq(IsolationPersonnel::getMoveStatus,moveStatus);
        IsolationPersonnel personnel = this.baseMapper.selectOne(query);
        return personnel;
    }

    private Integer checkPhone(String phone){
        LambdaQueryWrapper<IsolationPersonnel> query = new LambdaQueryWrapper<>();
        query.eq(IsolationPersonnel::getPhone,phone)
                .eq(IsolationPersonnel::getMoveStatus,"否");
        return this.baseMapper.selectCount(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String add(PersonnelAddRequest params) throws Exception {
//        IsolationPersonnel info = new IsolationPersonnel();
//        BeanUtils.copyProperties(params,info);
//        info.setMoveStatus(MoveType.NOT_MOVE);
//        info.setCreateTime(LocalDateTime.now());
//        info.setUpdateTime(LocalDateTime.now());
//        IsolationPersonnel check = check(info.getIdCard(),info.getMoveStatus());
//        Assert.isTrue(null == check, "该人员已填报");

//        String placeId = isolationPlaceMapper.getPlaceId(params.getPlaceName());
//
//        info.setPlaceId(placeId);

        //处理主记录
        IsolationPersonnel main = this.getInfo(params);
        //初始密码
        main.setPassword( DigestUtils.sha1Hex(PWD));
        this.baseMapper.insert(main);

        if(params.getCode()!=null){
            SmsLoginRequest smsLoginRequest = new SmsLoginRequest();
            smsLoginRequest.setCode(params.getCode());
            smsLoginRequest.setUsername(params.getPhone());
            loginService.smsPhone(smsLoginRequest);
        }


        //生成二维码
        main.setUnionFlag(main.getId());

        String base64 = qrcodeUtil.getQrCodeById(main.getId());
        main.setQrcode(base64);

        this.baseMapper.updateById(main);

        //判断是否有同行
        List<PersonnelAddRequest> list = params.getFamily();
        if(null != list && list.size() > 0){
            for (PersonnelAddRequest request : list){
                IsolationPersonnel info = new IsolationPersonnel();
                BeanUtils.copyProperties(main,info);
                String name = request.getName();
                String type = request.getImportantPersonnel();

                //证件是身份证，自动带入性别和年龄
                if(request.getDocumentType().equals("身份证")){
                    //身份证号
                    String idCard = request.getIdCard();
                    if(StringUtils.isNotBlank(idCard)){
                        info.setSex(IdCardUtil.getSex(request.getIdCard()));
                        info.setAge(IdCardUtil.getAge(request.getIdCard()));
                    }
                }
                else{
                    info.setAge(request.getAge());
                    info.setSex(request.getSex());
                }
                info.setDocumentType(request.getDocumentType());
                info.setIdCard(request.getIdCard());
                info.setName(name);
                info.setImportantPersonnel(type);
                info.setId(null);
                info.setUnionFlag(main.getId());
                info.setQrcode(base64);
                this.baseMapper.insert(info);
            }
        }

        return main.getId();
    }

    public IsolationPersonnel getInfo(PersonnelAddRequest params){
        IsolationPersonnel info = new IsolationPersonnel();
        BeanUtils.copyProperties(params,info);
        //处理性别和年龄
        if(params.getDocumentType().equals("身份证")){
            //身份证号
            String idCard = params.getIdCard();
            if(StringUtils.isNotBlank(idCard)){
                info.setSex(IdCardUtil.getSex(params.getIdCard()));
                info.setAge(IdCardUtil.getAge(params.getIdCard()));
            }
        }
        info.setMoveStatus(MoveType.NOT_MOVE);
        info.setCreateTime(LocalDateTime.now());
        info.setUpdateTime(LocalDateTime.now());
        IsolationPersonnel check = check(info.getIdCard(),info.getMoveStatus());
        Assert.isTrue(null == check, "该人员已填报");
        return info;
    }

    @Override
    public void update(PersonnelUpdateRequest params) throws Exception {
        IsolationPersonnel info = new IsolationPersonnel();
        BeanUtils.copyProperties(params,info);
        String placeId = isolationPlaceMapper.getPlaceId(params.getPlaceName());
        info.setPlaceId(placeId);
//        info.setUpdateTime(LocalDateTime.now());
//        info.setAuditStatus(ProcessStatus.PENDING_REVIEW);
        //接触后，修改房间状态
        if(params.getMoveStatus().equals("是")){
            isolationRoomMapper.updateStatus(placeId,params.getRoomNumber(),RoomType.DIRTY_ROOM);
        }
        this.baseMapper.updateById(info);
    }

    @Override
    public void updateMoveStatus(PersonnelUpdateMoveStatus params) {
        this.baseMapper.updateStatus(params);
    }

    @Override
    public void updateAuditStatus(PersonnelUpdateAuditStatus params) {
        IsolationPersonnel info = new IsolationPersonnel();
        BeanUtils.copyProperties(params,info);
        info.setAuditStatus(params.getAuditStatus());
        this.baseMapper.updateById(info);
    }

    @Override
    public IsolationPersonnel getIsolationByName(String username) {
        QueryWrapper<IsolationPersonnel> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(IsolationPersonnel::getPhone, username);
        wrapper.lambda().gt(IsolationPersonnel::getCreateTime,"2022-11-18 00:00:00");
        List<IsolationPersonnel> isolationPersonnels = getBaseMapper().selectList(wrapper);
        for (IsolationPersonnel isolationPersonnel : isolationPersonnels) {
            if (isolationPersonnel.getUnionFlag().equals(isolationPersonnel.getId())) {
                // 隔离后三天在今天之前
                if(isolationPersonnel!=null&& isolationPersonnel.getEndDate()!=null){
                    if (isolationPersonnel.getEndDate().plusDays(HOME_DAY).isBefore(LocalDateTime.now())) {
                        return null;
                    }
                }
                return isolationPersonnel;
            }
        }

        return null;
    }


}
